MapReduce হাদুপের একটি প্রোগ্রামিং মডেল এবং ডেটা প্রসেসিং ফ্রেমওয়ার্ক, যা বড় ডেটাসেট প্রক্রিয়াকরণের জন্য ব্যবহৃত হয়। এটি মূলত দুটি ধাপে কাজ করে: Map এবং Reduce।
MapReduce সমান্তরাল প্রক্রিয়াকরণের (Parallel Processing) মাধ্যমে বিতরণকৃত ডেটাসেট (Distributed Dataset) থেকে ডেটা বিশ্লেষণ এবং ফলাফল তৈরি করে।
MapReduce-এর দুটি ধাপ
Map (ম্যাপ ধাপ)
Map ফেজে ইনপুট ডেটাকে কী-ভ্যালু পেয়ার (Key-Value Pair) আকারে ভাগ করা হয়।
- ডেটা ব্লক আকারে পড়া হয়।
- প্রতিটি ব্লক থেকে কী-ভ্যালু জোড়া তৈরি হয়।
উদাহরণ:
যদি একটি টেক্সট ফাইলে একটি বাক্য থাকে:
Hello Hadoop Hello World
Map ধাপে এটি নিচের কী-ভ্যালু পেয়ারে রূপান্তরিত হবে:
(Hello, 1)
(Hadoop, 1)
(Hello, 1)
(World, 1)
Reduce (রিডিউস ধাপ)
Reduce ফেজে একই কী-র (Key) সব ভ্যালু যোগ করে চূড়ান্ত ফলাফল তৈরি করা হয়।
উদাহরণ:
উপরের Map আউটপুটকে Reduce ধাপে প্রসেস করলে ফলাফল হবে:
(Hello, 2)
(Hadoop, 1)
(World, 1)
এখানে দেখা যাচ্ছে "Hello" শব্দটি দুইবার এসেছে এবং বাকিগুলো একবার।
MapReduce প্রোগ্রামিং ওয়ার্কফ্লো
1. Input Splits
- ইনপুট ডেটা HDFS থেকে পড়া হয় এবং ছোট ছোট স্প্লিটে বিভক্ত করা হয়।
- প্রতিটি স্প্লিট Map টাস্কে পাঠানো হয়।
2. Map Phase
- Map ফাংশন ইনপুট ডেটার উপর কাজ করে কী-ভ্যালু পেয়ার তৈরি করে।
3. Shuffle and Sort
- Map আউটপুটের কী অনুযায়ী সব ভ্যালু একত্রিত করা হয়।
- কী-ভ্যালু পেয়ারগুলোকে গ্রুপ করে সাজানো হয়।
4. Reduce Phase
- Reduce ফাংশন একই কী-এর সব ভ্যালুকে যোগ করে চূড়ান্ত আউটপুট তৈরি করে।
5. Final Output
- Reduce আউটপুট HDFS-এ সংরক্ষণ করা হয়।
MapReduce উদাহরণ প্রোগ্রাম
নিচে একটি সাধারণ Word Count প্রোগ্রামের উদাহরণ দেওয়া হল:
Map Function
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class WordCountMapper
extends Mapper<Object, Text, Text, IntWritable> {
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context)
throws IOException, InterruptedException {
String[] words = value.toString().split(" ");
for (String str : words) {
word.set(str);
context.write(word, one);
}
}
}
Reduce Function
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class WordCountReducer
extends Reducer<Text, IntWritable, Text, IntWritable> {
public void reduce(Text key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
context.write(key, new IntWritable(sum));
}
}
MapReduce-এর সুবিধা
- বড় ডেটা প্রসেসিং: বিশাল আকারের ডেটা সহজে প্রসেস করা যায়।
- স্কেলেবিলিটি: নতুন নোড যুক্ত করে প্রসেসিং ক্ষমতা বাড়ানো যায়।
- Fault Tolerance: কোনো নোড ব্যর্থ হলে কাজ অন্য নোডে পুনরায় চালানো যায়।
- সিম্পল প্রোগ্রামিং মডেল: কী-ভ্যালু পেয়ার ভিত্তিক সিস্টেম সহজ এবং কার্যকর।
সারাংশ
MapReduce হাদুপের একটি কার্যকর ডেটা প্রসেসিং টুল, যা বড় ডেটাসেটকে সমান্তরালভাবে প্রসেস করে। এটি Map ধাপে ডেটাকে কী-ভ্যালু পেয়ারে বিভক্ত করে এবং Reduce ধাপে ডেটা বিশ্লেষণ করে চূড়ান্ত আউটপুট তৈরি করে। এর মাধ্যমে বড় ডেটা বিশ্লেষণ সহজ, দ্রুত এবং নির্ভরযোগ্যভাবে করা সম্ভব হয়।
MapReduce প্রোগ্রামে ডেটা প্রসেসিংয়ের জন্য Input Format এবং Output Format খুবই গুরুত্বপূর্ণ। এগুলো নির্ধারণ করে ডেটা কীভাবে পড়া হবে এবং কীভাবে আউটপুট ডেটা সংরক্ষণ করা হবে।
Input Format (ইনপুট ফরম্যাট)
Input Format মূলত ডেটার উৎস থেকে Map টাস্কে ডেটা কীভাবে পাঠানো হবে তা নির্ধারণ করে। এটি ইনপুট ডেটাকে স্প্লিট (Split) এবং কী-ভ্যালু পেয়ারে রূপান্তরিত করে।
বিভিন্ন ধরনের Input Format
1. TextInputFormat
- এটি ডিফল্ট Input Format।
- ইনপুট ডেটা লাইন-বাই-লাইন পড়া হয়।
- প্রতিটি লাইন একটি কী-ভ্যালু পেয়ার তৈরি করে।
- Key: লাইনটির অফসেট (Offset)।
- Value: লাইনটির টেক্সট।
উদাহরণ:
ইনপুট ডেটা:
Hello Hadoop
Hello World
Output কী-ভ্যালু পেয়ার:
(0, "Hello Hadoop")
(1, "Hello World")
2. KeyValueTextInputFormat
- এটি কী-ভ্যালু পেয়ার হিসেবে ইনপুট ডেটা পড়ে।
- ডেটার একটি ডিলিমিটার (Delimiter) ব্যবহার করা হয়, যেমন ট্যাব বা স্পেস।
উদাহরণ:
ইনপুট ডেটা:
word1 5
word2 10
Output কী-ভ্যালু পেয়ার:
("word1", 5)
("word2", 10)
3. SequenceFileInputFormat
- এটি বাইনারি ফাইল থেকে কী-ভ্যালু পেয়ার ইনপুট হিসেবে পড়ে।
- বড় ডেটাসেটের জন্য দ্রুত কাজ করে।
4. NLineInputFormat
- এটি প্রতিটি ইনপুট স্প্লিটে N সংখ্যক লাইন পড়ে।
- এটি লাইন সংখ্যা ভিত্তিক স্প্লিটিং করে।
উদাহরণ:
N = 2 হলে ইনপুট ডেটা:
Line1
Line2
Line3
Line4
Output স্প্লিট:
Split1: (0, "Line1\nLine2")
Split2: (1, "Line3\nLine4")
Output Format (আউটপুট ফরম্যাট)
Output Format নির্ধারণ করে কীভাবে রিডিউস (Reduce) আউটপুটকে সংরক্ষণ করা হবে।
বিভিন্ন ধরনের Output Format
1. TextOutputFormat
- এটি ডিফল্ট Output Format।
- কী-ভ্যালু পেয়ার টেক্সট আকারে সংরক্ষণ করা হয়।
উদাহরণ:
আউটপুট:
Hello 2
Hadoop 1
World 1
2. SequenceFileOutputFormat
- এটি বাইনারি ফরম্যাটে কী-ভ্যালু পেয়ার সংরক্ষণ করে।
- বড় আকারের ডেটার জন্য এটি বেশি কার্যকর।
3. MultipleOutputs
- এটি একাধিক আউটপুট ফাইল তৈরি করতে সাহায্য করে।
- উদাহরণস্বরূপ, আপনি বিভিন্ন কী অনুযায়ী আউটপুট ভাগ করতে পারেন।
4. NullOutputFormat
- কোনো আউটপুট সংরক্ষণ করা হয় না।
- এটি শুধুমাত্র প্রসেসিংয়ের জন্য ব্যবহৃত হয়।
Input এবং Output Format-এর ব্যবহার
Input Format সেট করা
MapReduce কোডে Input Format সেট করতে হয়:
job.setInputFormatClass(TextInputFormat.class);
Output Format সেট করা
Output Format নির্ধারণ করতে হয়:
job.setOutputFormatClass(TextOutputFormat.class);
সারাংশ
MapReduce প্রোগ্রামের Input Format ইনপুট ডেটাকে কীভাবে স্প্লিট এবং কী-ভ্যালু পেয়ারে রূপান্তর করবে তা নির্ধারণ করে। অন্যদিকে, Output Format চূড়ান্ত ফলাফল কীভাবে সংরক্ষণ করা হবে তা ঠিক করে। TextInputFormat এবং TextOutputFormat ডিফল্ট হিসেবে ব্যবহৃত হলেও অন্যান্য ফরম্যাট যেমন KeyValueTextInputFormat, SequenceFileInputFormat এবং MultipleOutputs বিভিন্ন প্রসেসিং প্রয়োজন অনুযায়ী ব্যবহার করা হয়।
হাদুপের MapReduce প্রোগ্রামে কাস্টম ডেটা টাইপ ব্যবহার করার জন্য Writable এবং WritableComparable ইন্টারফেস দুটি খুবই গুরুত্বপূর্ণ। এগুলো ডেটার রিডিং, রাইটিং এবং কম্পেয়ারিং প্রক্রিয়াগুলি নিয়ন্ত্রণ করে।
Writable Interface (Writable ইন্টারফেস)
Writable একটি হাদুপ ইন্টারফেস যা হাদুপ প্রোগ্রামগুলিতে কাস্টম অবজেক্টগুলোকে ডেটা স্টোরেজ এবং ট্রান্সফার করতে সক্ষম করে। যেকোনো কাস্টম ডেটা টাইপ, যা MapReduce প্রোগ্রামে ব্যবহার করা হবে, তাকে Writable ইন্টারফেস ইমপ্লিমেন্ট করতে হবে। এই ইন্টারফেস দুটি প্রধান মেথড প্রয়োজন:
void write(DataOutput out):
এই মেথডটি কাস্টম অবজেক্টের ডেটাকে বাইনারি ফরম্যাটে আউটপুট স্ট্রীমে লেখার কাজ করে।void readFields(DataInput in):
এই মেথডটি বাইনারি ফরম্যাট থেকে ডেটা পড়ে কাস্টম অবজেক্টে রূপান্তর করে।
Writable ইন্টারফেসের উদাহরণ
ধরা যাক, আমরা একটি Pair ক্লাস তৈরি করতে চাই, যা দুটি মান ধারণ করবে (যেমন String এবং Integer)। এই ক্লাসটি Writable ইন্টারফেস ইমপ্লিমেন্ট করবে।
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable;
public class Pair implements Writable {
private String key;
private int value;
// Getter and Setter methods
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(key);
out.writeInt(value);
}
@Override
public void readFields(DataInput in) throws IOException {
this.key = in.readUTF();
this.value = in.readInt();
}
}
উপরের উদাহরণে, Pair ক্লাসটি Writable ইন্টারফেস ইমপ্লিমেন্ট করেছে এবং write() এবং readFields() মেথডগুলিকে কাস্টম ডেটা টাইপের জন্য প্রয়োগ করা হয়েছে।
WritableComparable Interface (WritableComparable ইন্টারফেস)
WritableComparable ইন্টারফেস Writable ইন্টারফেসের একটি এক্সটেনশন যা ডেটা অবজেক্টের তুলনা (Comparison) করার ক্ষমতা দেয়। যখন কোনো কাস্টম ডেটা টাইপ WritableComparable ইন্টারফেস ইমপ্লিমেন্ট করে, তখন এটি ইনপুট বা আউটপুট ডেটাকে কম্পেয়ার করতে সক্ষম হয়।
WritableComparable ইন্টারফেসে একটি অতিরিক্ত মেথড থাকে:
int compareTo(T o):
এই মেথডটি দুটি অবজেক্টের তুলনা (Comparison) করে এবং ফলস্বরূপ একটি পূর্ণসংখ্যা রিটার্ন করে।- 0 রিটার্ন করলে, অর্থাৎ দুটি অবজেক্ট সমান।
- নেগেটিভ সংখ্যা রিটার্ন করলে, প্রথম অবজেক্ট দ্বিতীয় অবজেক্ট থেকে ছোট।
- পজিটিভ সংখ্যা রিটার্ন করলে, প্রথম অবজেক্ট দ্বিতীয় অবজেক্ট থেকে বড়।
WritableComparable ইন্টারফেসের উদাহরণ
ধরা যাক, আমরা Pair ক্লাসটি WritableComparable হিসেবে পরিবর্তন করতে চাই, যাতে আমরা এর অবজেক্টগুলি তুলনা করতে পারি।
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.Text;
public class Pair implements WritableComparable<Pair> {
private String key;
private int value;
// Getter and Setter methods
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(key);
out.writeInt(value);
}
@Override
public void readFields(DataInput in) throws IOException {
this.key = in.readUTF();
this.value = in.readInt();
}
@Override
public int compareTo(Pair other) {
int result = this.key.compareTo(other.key);
if (result == 0) {
result = Integer.compare(this.value, other.value);
}
return result;
}
}
এখানে, Pair ক্লাসটি WritableComparable ইন্টারফেস ইমপ্লিমেন্ট করেছে। compareTo() মেথডটি প্রথমে key তুলনা করে, এবং যদি key সমান হয়, তবে value তুলনা করে।
Writable এবং WritableComparable এর ব্যবহারের সুবিধা
- ডেটার ইম্প্লিমেন্টেশন সহজ: কাস্টম ডেটা টাইপের জন্য Writable এবং WritableComparable ব্যবহারের মাধ্যমে ডেটার স্টোরেজ এবং তুলনা সহজ হয়।
- দ্রুত ডেটা প্রক্রিয়াকরণ: সঠিকভাবে কাস্টম টাইপ ব্যবহার করলে প্রোগ্রাম আরও দ্রুত ও কার্যকরী হয়।
- ডেটা প্রক্রিয়াকরণের মধ্যে তুলনা: WritableComparable কম্পেয়ারবেল ডেটা ব্যবহার করে বিশেষভাবে ডেটার সাজানো এবং গ্রুপিং করতে সুবিধা দেয়।
সারাংশ
Writable এবং WritableComparable হাদুপে কাস্টম ডেটা টাইপ ব্যবহারের জন্য অপরিহার্য ইন্টারফেস। Writable ডেটা লিখা এবং পড়ার কাজ করে, যেখানে WritableComparable তুলনা করার জন্য ব্যবহৃত হয়। এগুলো MapReduce প্রোগ্রামে কাস্টম ডেটা প্রক্রিয়াকরণ ও শ্রেণীবদ্ধকরণের (Sorting) প্রক্রিয়া সহজতর করে।
হাদুপের MapReduce প্রোগ্রামিং মডেলে Combiner এবং Partitioners দুটি গুরুত্বপূর্ণ উপাদান, যা ডেটা প্রক্রিয়াকরণের দক্ষতা এবং পারফরম্যান্স বাড়াতে সাহায্য করে। এগুলি MapReduce প্রক্রিয়ায় ডেটা ট্রান্সফার এবং কম্পিউটেশনের কার্যকারিতা বৃদ্ধি করতে ব্যবহৃত হয়।
Combiner (কম্বাইনার) কী?
Combiner একটি অপশনাল ক্লাস যা MapReduce প্রোগ্রামে Map এবং Reduce এর মধ্যে অতিরিক্ত কম্পিউটেশন করতে ব্যবহৃত হয়। এটি Map স্টেজের পরে ইনপুট ডেটার আগেই কিছু কাজ সম্পন্ন করতে পারে, যেমন aggregation বা summarization। Combiner মূলত একটি Reduce ফাংশন হিসেবে কাজ করে, তবে এটি কেবলমাত্র Map টাস্কের জন্য তৈরি হয় এবং এটি সাধারণত ফেজ ১ (Map phase) এর পরে কম্পিউটেশন সম্পন্ন করে।
Combiner ব্যবহার করার সুবিধা
- নেটওয়ার্ক ট্রাফিক কমানো: Combiner ইনপুট ডেটা প্রক্রিয়াকরণ করার মাধ্যমে কম্পিউটেশন ও ট্রান্সফারের জন্য পাঠানো ডেটার আকার ছোট করে।
- পারফরম্যান্স বৃদ্ধি: এটি রিডিউসারের জন্য ডেটার আকার ছোট করে, ফলে Reduce ফেজের সময় কমে যায় এবং সম্পূর্ণ প্রক্রিয়া দ্রুত হয়।
- অপটিমাইজেশন: বড় ডেটাসেটের জন্য এটি কার্যকরী, কারণ এটি ইনপুট ডেটা কমিয়ে আনে এবং আরও দ্রুতভাবে ফলাফল দেয়।
Combiner-এর উদাহরণ
ধরা যাক, একটি Word Count প্রোগ্রামে Combiner ব্যবহার করতে চাই। এখানে, Combiner প্রতিটি শব্দের জন্য প্রাথমিকভাবে সঠিক গণনা করবে এবং পরে Reduce টাস্কে পাঠাবে।
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class WordCountCombiner extends Reducer<Text, IntWritable, Text, IntWritable> {
public void reduce(Text key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
context.write(key, new IntWritable(sum));
}
}
এখানে, Combiner প্রতিটি শব্দের গণনা করার পরে সেই তথ্যকে Reduce টাস্কে পাঠাবে, ফলে ডেটার আকার হ্রাস পাবে এবং Reduce ফেজ দ্রুত হবে।
Partitioner (পারটিশনার) কী?
Partitioner একটি ক্লাস যা MapReduce প্রোগ্রামে ডেটাকে বিভিন্ন Reduce টাস্কের মধ্যে ভাগ করার কাজ করে। এটি ডেটার অংশগুলোকে একাধিক রিডিউসারে ভাগ করার জন্য ব্যবহৃত হয়, যাতে রিডিউসাররা নির্দিষ্ট কী-এর উপর ভিত্তি করে ডেটা প্রসেস করতে পারে। Partitioner মূলত Map এবং Reduce এর মধ্যে যোগাযোগ স্থাপন করে এবং ডেটার বিভাজন নির্ধারণ করে।
Partitioner ব্যবহার করার সুবিধা
- লোড ব্যালেন্সিং: পার্টিশনার ডেটা ভাগ করে যে, প্রতিটি রিডিউসার সমানভাবে কাজ পায়। এটি সিস্টেমের লোড ব্যালেন্সিংয়ে সাহায্য করে।
- কাস্টম পদ্ধতিতে ডেটা ভাগ করা: ডিফল্ট পার্টিশনার যখন কিছু নির্দিষ্ট কী-ভ্যালু জোড়ার জন্য কাস্টম পদ্ধতি প্রয়োজন হয় তখন এটি ব্যবহার করা হয়।
- ডেটার বৈশিষ্ট্য অনুযায়ী ভাগ: বিভিন্ন ধরনের ডেটা যেমন সংখ্যার বিভিন্ন পরিসরের জন্য ভিন্ন পার্টিশনার ব্যবহার করা যায়।
Partitioner-এর উদাহরণ
ধরা যাক, আপনি একটি কাস্টম পার্টিশনার তৈরি করতে চান যা কী (key) অনুযায়ী ডেটা ভাগ করবে:
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
public class CustomPartitioner extends Partitioner<Text, IntWritable> {
@Override
public int getPartition(Text key, IntWritable value, int numPartitions) {
// "A" থেকে "M" পর্যন্ত প্রথম অংশে একটি পার্টিশন এবং "N" থেকে "Z" পর্যন্ত দ্বিতীয় অংশে অন্য পার্টিশন
String keyStr = key.toString().toUpperCase();
if (keyStr.charAt(0) < 'N') {
return 0; // প্রথম পার্টিশন
} else {
return 1; // দ্বিতীয় পার্টিশন
}
}
}
এখানে, CustomPartitioner কী-এর প্রথম অক্ষরের ভিত্তিতে ডেটা দুটি ভাগে (Partition) ভাগ করবে। এতে করে Map টাস্কের আউটপুট নির্দিষ্ট পার্টিশনে যাবে এবং Reduce টাস্কে ভালভাবে বিভাজিত হবে।
Combiner এবং Partitioner এর ব্যবহারের উপকারিতা
- Combiner ব্যবহারের মাধ্যমে:
- কম ট্রান্সফার ওভারহেড: ডেটার আকার কমাতে সাহায্য করে, ফলে ট্রান্সফারের সময় কমে যায়।
- দ্রুত রিডিউস: রিডিউসারদের জন্য ডেটার পরিমাণ কমিয়ে কাজের গতি বাড়ায়।
- Partitioner ব্যবহারের মাধ্যমে:
- লোড ব্যালেন্সিং: ডেটাকে সুষমভাবে ভাগ করার মাধ্যমে সিস্টেমের ভারসাম্য বজায় রাখা যায়।
- কাস্টমাইজড ভাগ: ডেটার স্পেসিফিক বৈশিষ্ট্যের উপর ভিত্তি করে কাস্টম ভাগ করা যায়, যা পারফরম্যান্স বাড়ায়।
সারাংশ
Combiner এবং Partitioner হাদুপের MapReduce প্রোগ্রামে কার্যকারিতা বৃদ্ধি করার জন্য গুরুত্বপূর্ণ টুল। Combiner ইনপুট ডেটার আংশিকভাবে প্রক্রিয়াকরণ করে এবং কম্পিউটেশন কমিয়ে আনে, যেখানে Partitioner ডেটাকে সমানভাবে বিভিন্ন রিডিউসারে ভাগ করে লোড ব্যালেন্সিং নিশ্চিত করে। এই দুটি উপাদান ডেটা ট্রান্সফার এবং প্রসেসিং কে দ্রুত, কার্যকর এবং স্কেলেবল করে তোলে।
হাদুপ (Hadoop) এর MapReduce মডেল প্রধানত বড় ডেটাসেটের সমান্তরাল প্রক্রিয়াকরণে ব্যবহৃত হয়। তবে, কিছু পরিস্থিতিতে Secondary Sorting এবং Joins-এর মতো উন্নত (Advanced) কৌশলগুলি প্রয়োগ করা প্রয়োজন, যাতে আরও জটিল ডেটা প্রসেসিং এবং বিশ্লেষণ সম্ভব হয়। এই প্রযুক্তিগুলি বড় ডেটা প্রক্রিয়াকরণের প্রয়োজনীয়তা মেটাতে সাহায্য করে।
Secondary Sorting
Secondary Sorting হল একটি প্রক্রিয়া যেখানে MapReduce কাজের সময় ডেটা বিভিন্ন ক্রমে সাজানো হয়। সাধারণত, হাদুপের MapReduce ফেজে Sort করার সময় কী (Key) অনুযায়ী ডেটা সাজানো হয়। কিন্তু অনেক সময় আমাদের secondary key বা secondary sort করতে হয়, যেখানে প্রথম কী একসাথে সাজানো থাকে, এবং দ্বিতীয় কী অনুযায়ী ডেটা সাজানো হয়।
Secondary Sorting কেন দরকার?
MapReduce-এর Shuffle and Sort পর্যায়ে শুধুমাত্র মূল কী (Primary Key) অনুযায়ী ডেটা সাজানো হয়, কিন্তু কিছু ক্ষেত্রে একাধিক কী-এর ওপর ভিত্তি করে সাজানোর প্রয়োজন হতে পারে। Secondary Sorting ব্যবহার করে এই সমস্যার সমাধান করা যায়, যাতে একই কী-এর মধ্যে অন্য কী (Secondary Key) অনুযায়ী ডেটা সাজানো হয়।
Secondary Sorting এর উদাহরণ
ধরা যাক, আপনার কাছে কিছু Student নামের ডেটা রয়েছে, যেখানে প্রথম কী হলো Student Name এবং দ্বিতীয় কী হলো Marks। আপনি যদি প্রথমে নাম অনুযায়ী সাজাতে চান, কিন্তু তারপরে একই নামের শিক্ষার্থীদের মার্কসের ওপর ভিত্তি করে সাজাতে চান, তবে Secondary Sorting ব্যবহার করা হবে।
Secondary Sorting বাস্তবায়ন
Secondary Sorting বাস্তবায়নের জন্য, আপনাকে কিছু অতিরিক্ত পদক্ষেপ নিতে হবে:
- Custom Writable Comparable তৈরি করুন:
আপনাকে WritableComparable ইন্টারফেস ইমপ্লিমেন্ট করে একটি কাস্টম কিও-ব্লক তৈরি করতে হবে, যা প্রথম কী এবং দ্বিতীয় কী (Secondary Key) ধারণ করবে। - Map Function:
Map ফেজে আপনি কাস্টম কী-ভ্যালু পেয়ার তৈরি করবেন এবং এই কাস্টম কী অনুযায়ী Sorting করতে পারবেন। - Sort Function:
Sort ফেজে আপনাকে Secondary Sorting এর জন্য Comparator সেট করতে হবে।
Joins in Hadoop MapReduce
Joins হাদুপের MapReduce-এ একটি গুরুত্বপূর্ণ টেকনিক যা আপনাকে দুটি বা ততোধিক ডেটাসেটের মধ্যে সম্পর্ক (Relation) তৈরি করতে দেয়। সাধারণত, একাধিক ডেটাসেটের মধ্যে সম্পর্ক বের করতে Join ব্যবহৃত হয়। কিন্তু MapReduce এর প্রথাগত পদ্ধতিতে দুটি ডেটাসেটের মধ্যে Join করার কাজটি একটু জটিল হতে পারে।
Types of Joins
হাদুপে তিন ধরনের Join টেকনিক ব্যবহৃত হয়:
1. Map-side Join
Map-side Join তখন ব্যবহার করা হয় যখন দুটি ডেটাসেট ছোট এবং একে অপরের সাথে সম্পর্কিত থাকে। এই প্রক্রিয়ায় ডেটাগুলিকে মেমোরিতে লোড করা হয় এবং Map ফেজে ডেটা Join করা হয়। এটি Reduce ফেজে লোড ও শফলিং অপারেশন কমিয়ে দেয়, ফলে এটি দ্রুত এবং আরও কার্যকরী হয়।
Map-side Join বাস্তবায়ন:
public class MapSideJoinMapper extends Mapper<LongWritable, Text, Text, Text> {
private Map<String, String> lookupTable = new HashMap<>();
protected void setup(Context context) throws IOException, InterruptedException {
// ছোট ডেটাসেটটি মেমোরিতে লোড করা
Configuration conf = context.getConfiguration();
String fileName = conf.get("lookup.file");
Path path = new Path(fileName);
FileSystem fs = FileSystem.get(conf);
BufferedReader reader = new BufferedReader(new InputStreamReader(fs.open(path)));
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");
lookupTable.put(parts[0], parts[1]);
}
}
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// ডেটা Join করা
String[] record = value.toString().split(",");
String lookupValue = lookupTable.get(record[0]);
if (lookupValue != null) {
context.write(new Text(record[0]), new Text(record[1] + "," + lookupValue));
}
}
}
2. Reduce-side Join
Reduce-side Join তখন ব্যবহার করা হয় যখন দুটি ডেটাসেট খুব বড় এবং মেমোরিতে লোড করা সম্ভব নয়। এই পদ্ধতিতে ডেটাগুলি Shuffle and Sort ফেজে একত্রিত হয় এবং Reduce ফেজে একসাথে যোগ করা হয়। যদিও এটি ধীরগতিতে কাজ করতে পারে, তবে এটি বড় ডেটাসেটের জন্য কার্যকর।
Reduce-side Join বাস্তবায়ন:
public class ReduceSideJoinReducer extends Reducer<Text, Text, Text, Text> {
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
String value1 = null;
for (Text val : values) {
if (value1 == null) {
value1 = val.toString(); // প্রথম ডেটাসেটের মান
} else {
context.write(key, new Text(value1 + "," + val.toString())); // Join করা
}
}
}
}
3. Composite Join
Composite Join একটি সংমিশ্রিত পদ্ধতি, যেখানে Map-side Join এবং Reduce-side Join এর সংমিশ্রণ ঘটানো হয়। এটি তখন ব্যবহৃত হয় যখন একাধিক ডেটাসেটের মধ্যে সম্পর্ক তৈরি করতে হয়।
সারাংশ
হাদুপে Secondary Sorting এবং Joins বেশ গুরুত্বপূর্ণ এবং শক্তিশালী টেকনিক। Secondary Sorting দুটি কী অনুযায়ী ডেটা সাজাতে সাহায্য করে, যেখানে Joins বিভিন্ন ডেটাসেটের মধ্যে সম্পর্ক তৈরি করতে ব্যবহৃত হয়। Map-side Join এবং Reduce-side Join উভয়ই বড় ডেটাসেটের মধ্যে সম্পর্ক সৃষ্টি করতে ব্যবহার করা হয়, তবে একে অপরের মধ্যে পারফরমেন্স পার্থক্য থাকতে পারে, নির্ভর করে ডেটার আকার এবং কাঠামোর ওপর।
Read more